-- BonusM
-- created by panyl
-- 奖励模块

module("BonusM", package.seeall);

-- 奖励配置
local config = {};

-- 收集一个区间内获得的奖励， 通过startBonusCollect() 开始收集， endBonusCollect() 结束收集
local bonusCollect = {};
local bonusCollecting = false;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 转换下bonus信息表
    config = {};
    local bonus_CSV = get_bonus_CSV();
    for i = 1, #bonus_CSV do
        config[bonus_CSV[i].id] = bonus_CSV[i];
    end
end

-- 模块初始化操作
function init()
    loadCsv();
end

-- 检索
function query(id, path)
    local m = config[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

------------------------
-- 执行奖励
-- @param bonus  奖励配置（数组类型）
-- @param desc   奖励简要描述
-- @param noCollect 是否收集（默认值为要收集(true)）。为false时将不记录bonusCollect
function doBonus(bonus, desc, noCollect)
    Profiler.funcBegin("doBonus");

    local result = true;
    -- 没有该类奖励
    if not config[bonus[1]] then
        return false;
    end

    if bonus[3] <= 0 then
        return false;
    end

    -- 除称号奖励外，大地之门最多一本
    if bonus[2] == 4005 and desc ~= "career_bonus" then
        local hasBackFloor = ME.user.dbase:query("has_back_floor", 0);
        if hasBackFloor >= 1 + 1 - bonus[3] then
            local rand =  DungeonM.getRandSeed("has_back_floor");
            if desc == "prop gift" then
                -- 转为同系别卷轴
                local arr = { 4001, 4002, 4003, 4004, };
                bonus[2] = arr[1 + rand % 4];
            else
                -- 转为同阶位卷轴
                local arr = { 4015, 4025, 4035, 4045, 4055, };
                bonus[2] = arr[1 + rand % 5];
            end
        else
            ME.user.dbase:set("has_back_floor", bonus[3] + hasBackFloor);
        end
    end

    if ItemM.query(bonus[2], "type") == ITEM_TYPE_SPELL then
        local props = PropM.fetchProps(ME.user, "change_spell");
        local prop;
        for _, prop in ipairs(props) do
            bonus[2] = PropM.trigger(ME.user, prop[1], prop[2], bonus[2]);
        end

        props = PropM.fetchProps(ME.user, "change_spell2");
        for _, prop in ipairs(props) do
            bonus[2] = PropM.trigger(ME.user, prop[1], prop[2], bonus[2]);
        end

        props = PropM.fetchProps(ME.user, "double_reel");
        for _, prop in ipairs(props) do
            bonus[3] = bonus[3] + PropM.trigger(ME.user, prop[1], prop[2], bonus);
        end
    end

    -- 特定史莱姆转换物品
    local transItem = FormulaM.invoke("GET_SLIME_TRANS_ITEM", bonus[2]);
    if transItem then
        bonus[2] = transItem;
    end

    if type(noCollect) ~= "boolean" then
        noCollect = true;
    end
    if noCollect ~= false and bonusCollecting then
        table.insert(bonusCollect, bonus);
    end

    local count = bonus[3];

    if config[bonus[1]].bonus == "item" then
        -- 物品奖励
        result = itemBonus(bonus[2], count, desc);

    elseif config[bonus[1]].bonus == "attrib" then
        local attrib = bonus[2];

        -- 如果是hp、mp，不能超过最大值
        if attrib == "hp" or attrib == "limit_hp" then
            if true ~= DungeonM.canRecoverAttrib(ME.user, attrib) then
                -- 经判断，无法获得属性
                return;
            end

            -- 可以超上限
            if "limit_hp" == attrib and ME.user:queryAttrib("max_hp") <= ME.user:queryAttrib("hp") then
                -- 当前血量已经达到上限了，提升一点
                count = 1;
                attribBonus("max_hp", count, desc);
            else
                -- 不能超出上限
                count = math.min(count, ME.user:queryAttrib("max_hp") - ME.user:queryAttrib("hp"));
            end

            attrib = "hp";
        elseif attrib == "mp" or attrib == "limit_mp" then
            if true ~= DungeonM.canRecoverAttrib(ME.user, attrib) then
                -- 经判断，无法获得属性
                return;
            end

            -- 可以超上限
            if "limit_mp" == attrib and ME.user:queryAttrib("max_mp") <= ME.user:queryAttrib("mp") then
                -- 提升一点
                count = 1;
                attribBonus("max_mp", count, desc);
            else
                -- 不能超出上限
                count = math.min(count, ME.user:queryAttrib("max_mp") - ME.user:queryAttrib("mp"));
            end

            attrib = "mp";
        elseif attrib == "exp" then
            -- 如果已经满级，不能再获得经验
            if ME.user:getLevel() >= MAX_USER_LEVEL then
                count = 0;
            end
        elseif attrib == "life" then
            -- 体力最多回满至上限
            local delta = math.max(0, LIMIT_USER_LIFE - ME.user.dbase:query("life", 0));
            count = math.min(delta, count);
        end

        bonus[3] = count;

        attribBonus(attrib, count, desc);

        -- 如果是最大血量
        if attrib == "max_hp" then
            attribBonus("hp", count, desc);
        elseif attrib == "max_mp" then
            attribBonus("mp", count, desc);
        end
    elseif config[bonus[1]].bonus == "hero" then
        -- 英雄奖励
        result = heroBonus(tonumber(bonus[2]), bonus[3]);
    elseif config[bonus[1]].bonus == "talent" then
        -- 天赋奖励
        talentBonus(bonus[2]);
    elseif config[bonus[1]].bonus == "map" then
        -- 地图奖励
        mapBonus(bonus[2]);
    elseif config[bonus[1]].bonus == "ship_skill" then
        -- 飞艇技能（秘宝）
        shipSkillBonus(bonus[2], bonus[3]);
    elseif config[bonus[1]].bonus == "robot" then
        -- 机器人
        SkyRobotM.addRobot(bonus[2], bonus[3]);
    elseif config[bonus[1]].bonus == "equip_exp" then
        -- 装备奖励经验
        EquipM.addSpecialEquipExp(bonus[2], bonus[3]);
    end

    -- 奖励事件
    EventMgr.fire(event.DO_BONUS, bonus);

    Profiler.funcEnd("doBonus");

    return result;
end

-- 奖励物品
function itemBonus(classId, count, desc)
    -- 转化掉了(只有一种转化目标)
    local prop = PropM.combine(ME.user, "item_exchange", classId);
    if prop[3] > 0 then
        classId = prop[3];
    end

    -- 物品奖励
    ItemM.addAmount(ME.user, classId, count, {["desc"] = desc,});

    -- 记录奖励的可携带道具
    if DungeonM.isInDungeon() and ItemM.isCarriableItem(classId) and not DungeonM.isPause() then
        local dungeonItem = ME.user.dbase:query("dungeon_item", {});
        if dungeonItem[classId] == nil then
            dungeonItem[classId] = 0;
        end
        dungeonItem[classId] = dungeonItem[classId] + count;
        ME.user.dbase:set("dungeon_item", dungeonItem);
    end

    -- 记录可以被带出地牢的道具
    if DungeonM.isInDungeon() and ItemM.isTakeOutItem(classId) and not DungeonM.isPause() then
        local takeOutItem =  ME.user.dbase:query("take_out_item", {});
        if takeOutItem[classId] == nil then
            takeOutItem[classId] = 0;
        end
        takeOutItem[classId] = takeOutItem[classId] + count;
        ME.user.dbase:set("take_out_item", takeOutItem);
    end

    -- 炼金师宝物研究
    if ItemM.query(classId, "type") == ITEM_TYPE_TREASURE or
       ItemM.query(classId, "type") == ITEM_TYPE_SPECIAL_TREASURE then
        local props = PropM.fetchProps(ME.user, "treasure_get_item")
        for _, prop in ipairs(props) do
            PropM.trigger(ME.user, prop[1], prop[2], classId);
        end
    end

    return {1, classId, count, };
end

-- 属性奖励
function attribBonus(attrib, count, desc)
    ME.user:addAttrib(attrib, count, desc);
end

-- 英雄奖励
function heroBonus(classId, count)
    -- 如果玩家还没有该英雄
    if not ME.user.pets[classId] then
        -- 获得英雄
        PetM.addPet(classId);
        return {id = 3, classId = classId, count = count };
    end

    -- 玩家已经有该英雄，改为奖励徽章碎片
    local bonus = FormulaM.invoke("CALC_HERO_TO_MATERIAL", ME.user.pets[classId]);
    itemBonus(bonus[2], bonus[3]);
    return {id = 1, classId = bonus[2], count = bonus[3] };
end

-- 天赋奖励
function talentBonus(skillId)
    TalentM.activateTalent(skillId);
end

-- 地图奖励
function mapBonus(dungeonId)
    DungeonAreaM.forceUnlockArea(ME.user, dungeonId);
end

-- 飞艇技能（秘宝）奖励
function shipSkillBonus(skillId, progress)
    SkyShipSkillM.addProgress(skillId, progress);
end

-- 开始奖励收集
function startBonusCollect()
    bonusCollecting = true;
end

-- 结束奖励收集
function endBonusCollect()
    bonusCollecting = false;
end

-- 获取奖励收集列表
function getBonusCollect()
    return bonusCollect;
    -- return {{2, "hp", 1}, {2, "mp", 1}, {2, "search_point", 1}, {1, 4001, 1}, {1, 5011, 1}};
end

-- 清除奖励收集列表
function clearBonusCollect()
    bonusCollect = {};
end

-- 合并同类奖励
-- 例如：
-- bonus = { { 2, "money", 1000 }, { 2, "money", 1000 }, }
-- 合并后的结果为：{ { 2, "money", 2000 }, }
function combineBonus(bonus)
    local ret = {};
    for _, arr in ipairs(bonus) do
        local isExist = false;
        for _, arr2 in ipairs(ret) do
            if arr[1] == arr[1] and arr[2] == arr2[2] then
                arr2[3] = arr2[3] + arr[3];
                isExist = true;
            end
        end

        if not isExist then
            table.insert(ret, arr);
        end
    end
    return ret;
end

-- 判断消耗是否足够
function isUserCostEnough(cost)
    for _, arr in pairs(cost) do
        if arr[1] == 1 then
            if ItemM.getAmount(ME.user, arr[2]) < arr[3] then
                return false;
            end
        elseif arr[1] == 2 then
            if ME.user:queryAttrib(arr[2]) < arr[3] then
                return false;
            end
        end
    end

    return true;
end
